<template>
  <view v-if="isOpen" class="file-outerBox" @touchmove.prevent>
    <view style="width: 100%; padding-top: --status-bar-height;" />
    <view class="file-titel" :style="{ backgroundColor: navBgColor }">
      <view class="file-nav-leftBox" @click="backAddress">
        <image :src="backImg" mode="widthFix" class="file-back-img" />
      </view>
      <text :style="titelStyle">
        {{ titel }}
      </text>
      <view class="file-nav-rightBox" />
    </view>
    <view class="file-address">
      <view class="root-box" @click="backRoot">
        内部存储
        <image :src="directionImg" mode="widthFix" class="to-img-box" />
      </view>
      <scroll-view :scroll-x="true" class="address-scroll">
        <view v-for="(item, index) in addressBar" class="address-box" @click="backFolder(item, index)">
          {{ item.name }}
          <image :src="directionImg" mode="widthFix" class="to-img-box" />
        </view>
      </scroll-view>
    </view>
    <view class="">
      <scroll-view :scroll-y="true" :style="{ height: `calc(100vh - ${barHeight * 2 + 280}rpx)` }">
        <view v-if="inaccessible" class="select-tips">
          <view style="line-height: 40rpx;">
            无法访问的文件夹
          </view>
          <view style="line-height: 40rpx;">
            建议前往安卓存储访问框架查看文件
          </view>
        </view>
        <view v-for="item in folderArr" class="folder-box" @click="toFolder(item)">
          <view class="folder-name-box">
            <image :src="folderImg" mode="widthFix" class="folder-img" />
            <view class="name-box">
              {{ item.name }}
            </view>
          </view>
          <view>
            <image :src="enterImg" mode="widthFix" class="toFolder-img" />
          </view>
        </view>
        <view v-for="(item, index) in fileArr" class="file-box" @click="selectFile(index)">
          <view class="file-name-box">
            <image v-if="item.type === 'file'" :src="fileImg" mode="widthFix" class="file-img" />
            <image v-if="item.type === 'txt'" :src="txtImg" mode="widthFix" class="file-img" />
            <image v-if="item.type === 'doc'" :src="docImg" mode="widthFix" class="file-img" />
            <image v-if="item.type === 'pdf'" :src="pdfImg" mode="widthFix" class="file-img" />
            <view class="name-box">
              {{ item.name }}
            </view>
          </view>
          <view>
            <image v-if="item.select" :src="selectedImg" mode="widthFix" class="select-img" />
            <image v-else :src="unselectedImg" mode="widthFix" class="select-img" />
          </view>
        </view>
      </scroll-view>
    </view>
    <view class="">
      <button type="default" class="select-foot-btn" :style="btnStyle" @click="uploadBtn">
        {{ btnText }}
      </button>
    </view>
  </view>
</template>

<script>
/*
*
* {property} 使用 v-model 绑定一个变量来控制组件的开启与关闭
* {property} navBgColor [String] 顶部标题栏背景色
* {property} folderImg [String] 文件夹的图片
* {property} backImg [String] 返回上一级图片
* {property} directionImg [String] 右指向箭头
* {property} enterImg [String] 进入文件夹箭头
* {property} fileImg [String] 未知文件通用图标，当前仅可识别 pdf、doc/docx、txt
* {property} txtImg [String] txt文件图标
* {property} docImg [String] doc/docx文件图标
* {property} pdfImg [String] pdf文件图标
* {property} selectedImg [String] 选中状态下的按钮图标
* {property} unselectedImg [String] 未选中状态下的按钮图标
* {property} titel [String] 标题文字，默认 '选择文件'
* {property} titelSize [String,Number] 标题文字大小，默认 36rpx
* {property} titelWeight [String,Number] 标题文字粗细，默认 600
* {property} titelColor [String] 标题文字颜色，默认 #373737
* {property} btnText [String] 底部按钮文字， 默认 '上传'
* {property} btnSize [String,Number] 底部按钮文字大小， 默认 36rpx
* {property} btnHeight [String,Number] 底部按钮高度， 默认 92rpx
* {property} btnBgColor [String] 底部按钮颜色， 默认 #6521e2
* {property} btnTextColor [String] 底部按钮文字颜色， 默认 #fff
* {property} filterArr [Array] 筛选文件类型，示例：['doc','PDF']，不区分大小写
*
* {event} confirm [Function] 点击上传按钮触发的回调事件，会返回选中文件的地址 event = [{name: name, url: path, sizeMB: sizeMb}]
*   name: 文件名  url: 文件地址  sizeMB: 文件大小，单位MB
*/

export default {
  name: 'NkSelectFile',
  props: {
    modelValue: {
      type: Boolean,
      default: false
    },
    backImg: {
      type: String,
      default: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-5c697db4-d920-4af3-90a0-19211379b881/c08ef3dc-2514-443d-91aa-a055a098077f.png'
    },
    directionImg: {
      type: String,
      default: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-5c697db4-d920-4af3-90a0-19211379b881/183fcda4-b046-4723-8356-dded284bdefc.png'
    },
    enterImg: {
      type: String,
      default: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-5c697db4-d920-4af3-90a0-19211379b881/138ad94e-84e5-460e-a4eb-9e29d2139049.png'
    },
    folderImg: {
      type: String,
      default: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-5c697db4-d920-4af3-90a0-19211379b881/7f70ee21-bd9c-4630-9a0a-113d78a99335.png'
    },
    fileImg: {
      type: String,
      default: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-5c697db4-d920-4af3-90a0-19211379b881/24fe2fda-a956-402e-af65-e11f8779c6d1.png'
    },
    txtImg: {
      type: String,
      default: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-5c697db4-d920-4af3-90a0-19211379b881/10450e01-189b-48c7-9b97-918104fdd701.png'
    },
    docImg: {
      type: String,
      default: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-5c697db4-d920-4af3-90a0-19211379b881/501660e5-8386-473f-bfcb-34c0b2b4a2f8.png'
    },
    pdfImg: {
      type: String,
      default: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-5c697db4-d920-4af3-90a0-19211379b881/b1056050-6d27-454e-b2b7-51e3832cfe5e.png'
    },
    selectedImg: {
      type: String,
      default: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-5c697db4-d920-4af3-90a0-19211379b881/ebaaad9d-4697-42d1-beea-f4c736132b9a.png'
    },
    unselectedImg: {
      type: String,
      default: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-5c697db4-d920-4af3-90a0-19211379b881/ea5fe3fa-799b-40c9-be01-00d0b7419c4a.png'
    },
    titel: {
      type: String,
      default: '选择文件'
    },
    titelSize: {
      type: [String, Number],
      default: 36
    },
    titelWeight: {
      type: [String, Number],
      default: 600
    },
    titelColor: {
      type: String,
      default: '#373737'
    },
    btnText: {
      type: String,
      default: '上传'
    },
    btnSize: {
      type: [String, Number],
      default: 36
    },
    btnHeight: {
      type: [String, Number],
      default: 92
    },
    btnBgColor: {
      type: String,
      default: '#6521e2'
    },
    btnTextColor: {
      type: String,
      default: '#fff'
    },
    navBgColor: {
      type: String,
      default: '#fff'
    },
    filterArr: {
      type: Array,
      default() {
        return []
      }
    }
  },
  data() {
    return {
      barHeight: '', // 状态栏高度
      rootAddress: {}, // 根目录
      addressBar: [], // 地址栏记录栈
      folderArr: [], // 文件夹
      fileArr: [], // 文件
      selectArr: [], // 选中文件集合
      isExit: true, // 退出
      isOpen: false,
      inaccessible: false, // 无法访问提示
      titelStyle: {
        fontSize: `${this.titelSize}rpx`,
        fontWeight: this.titelWeight,
        color: this.titelColor
      },
      btnStyle: {
        height: `${this.btnHeight}rpx`,
        backgroundColor: this.btnBgColor,
        color: this.btnTextColor,
        fontSize: `${this.btnSize}rpx`
      },
      filterReg: ''
    }
  },
  watch: {
    modelValue(val) {
      if (val) {
        this.open()
      }
      else {
        this.close()
      }
    }
  },
  mounted() {
    if (Object.prototype.toString.call(this.filterArr) === '[object Array]' && this.filterArr.length > 0) {
      const str = this.filterArr.join('|')
      this.filterReg = new RegExp(str, 'i')
    }
  },
  methods: {
    // 打开组件
    open() {
      this.isOpen = true
      this.getBarHeight()
      this.getRootDirectory()
    },
    // 关闭组件
    close() {
      this.isOpen = false
      this.rootAddress = {} // 根目录
      this.addressBar = [] // 地址栏记录栈
      this.folderArr = []
      this.fileArr = []
      this.selectArr = [] // 选中文件集合
      this.$emit('update:modelValue', false)
      // 放到下一个生命周期，因为双向绑定的value修改父组件状态需要时间，且是异步的
      this.$nextTick(() => {
        this.$emit('change', false)
      })
    },

    // 获取状态栏高度
    getBarHeight() {
      uni.getSystemInfo({
        success: (res) => {
          this.barHeight = res.statusBarHeight
        }
      })
    },
    // 获取根目录
    getRootDirectory() {
      this.inaccessible = false
      // 修改退出状态，以便在点击返回按钮时最后一层返回的是根目录，再点击一次才会退出
      this.isExit = false
      this.addressBar = []
      const environment = plus.android.importClass('android.os.Environment')
      environment.getExternalStorageState() === environment.MEDIA_MOUNTED
      const sdRoot = environment.getExternalStorageDirectory()
      const rootName = plus.android.invoke(sdRoot, 'getName')
      this.rootAddress = {
        name: rootName,
        file: sdRoot
      }
      const files = plus.android.invoke(sdRoot, 'listFiles')
      if (!(Object.prototype.toString.call(files) === '[object Array]')) {
        uni.showToast({
          icon: 'none',
          title: '请确认授权访问',
          duration: 2000
        })
        return
      }
      const len = files.length
      for (let i = 0; i < len; i++) {
        // 过滤隐藏文件
        if (!plus.android.invoke(files[i], 'isHidden')) {
          // 判断是文件还是文件夹
          if (plus.android.invoke(files[i], 'isDirectory')) {
            const folderName = plus.android.invoke(files[i], 'getName')
            this.folderArr.push({ name: folderName, file: files[i] })
          }
          else {
            const fileName = plus.android.invoke(files[i], 'getName')
            if (this.filterArr.length > 0) {
              if (fileName.search(this.filterReg) < 0) {
                continue
              }
            }
            if (fileName.search(/txt/i) > -1) {
              // txt 文件
              this.fileArr.push({ name: fileName, file: files[i], type: 'txt', select: false })
            }
            else if (fileName.search(/doc|docx/i) > -1) {
              // doc/docx 文件
              this.fileArr.push({ name: fileName, file: files[i], type: 'doc', select: false })
            }
            else if (fileName.search(/pdf/i) > -1) {
              // pdf 文件
              this.fileArr.push({ name: fileName, file: files[i], type: 'pdf', select: false })
            }
            else {
              // 其他文件
              this.fileArr.push({ name: fileName, file: files[i], type: 'file', select: false })
            }
          }
        }
      }
      // 排序，不区分大小写
      this.folderArr.sort((a, b) => { return a.name.toUpperCase() > b.name.toUpperCase() ? '1' : '-1' })
      this.fileArr.sort((a, b) => { return a.name.toUpperCase() > b.name.toUpperCase() ? '1' : '-1' })
      this.rootAddress.folderArr = this.folderArr
      this.rootAddress.fileArr = this.fileArr
    },
    // 进入文件夹
    toFolder(event) {
      this.isExit = false // 地址栈中存在新地址，重置退出状态
      this.folderArr = []
      this.fileArr = []
      this.addressBar.push(event)
      const files = plus.android.invoke(event.file, 'listFiles')
      if (files === null) {
        this.inaccessible = true
      }
      const len = files.length
      for (let i = 0; i < len; i++) {
        // 过滤隐藏文件
        if (!plus.android.invoke(files[i], 'isHidden')) {
          // 判断是文件还是文件夹
          if (plus.android.invoke(files[i], 'isDirectory')) {
            const folderName = plus.android.invoke(files[i], 'getName')
            this.folderArr.push({ name: folderName, file: files[i] })
          }
          else {
            const fileName = plus.android.invoke(files[i], 'getName')
            if (this.filterArr.length > 0) {
              if (fileName.search(this.filterReg) < 0) {
                continue
              }
            }
            if (fileName.search(/txt/i) > -1) {
              // txt 文件
              this.fileArr.push({ name: fileName, file: files[i], type: 'txt', select: false })
            }
            else if (fileName.search(/doc|docx/i) > -1) {
              // doc/docx 文件
              this.fileArr.push({ name: fileName, file: files[i], type: 'doc', select: false })
            }
            else if (fileName.search(/pdf/i) > -1) {
              // pdf 文件
              this.fileArr.push({ name: fileName, file: files[i], type: 'pdf', select: false })
            }
            else {
              // 其他文件
              this.fileArr.push({ name: fileName, file: files[i], type: 'file', select: false })
            }
          }
        }
      }
      // 排序，不区分大小写
      this.folderArr.sort((a, b) => { return a.name.toUpperCase() > b.name.toUpperCase() ? '1' : '-1' })
      this.fileArr.sort((a, b) => { return a.name.toUpperCase() > b.name.toUpperCase() ? '1' : '-1' })
    },
    // 返回根目录
    backRoot() {
      this.inaccessible = false
      this.addressBar = []
      this.folderArr = this.rootAddress.folderArr
      this.fileArr = this.rootAddress.fileArr
    },
    // 返回上级文件夹
    backFolder(event, index) {
      this.inaccessible = false
      let len = this.addressBar.length
      if (index + 1 === len) {
        // 点击当前文件夹--无事发生

      }
      else {
        this.folderArr = []
        this.fileArr = []
        this.addressBar.splice(index + 1, len - index + 1)
        const files = plus.android.invoke(event.file, 'listFiles')
        len = files.length
        for (let i = 0; i < len; i++) {
          // 过滤隐藏文件
          if (!plus.android.invoke(files[i], 'isHidden')) {
            // 判断是文件还是文件夹
            if (plus.android.invoke(files[i], 'isDirectory')) {
              const folderName = plus.android.invoke(files[i], 'getName')
              this.folderArr.push({ name: folderName, file: files[i] })
            }
            else {
              const fileName = plus.android.invoke(files[i], 'getName')
              if (this.filterArr.length > 0) {
                if (fileName.search(this.filterReg) < 0) {
                  continue
                }
              }
              if (fileName.search(/txt/i) > -1) {
                // txt 文件
                this.fileArr.push({ name: fileName, file: files[i], type: 'txt', select: false })
              }
              else if (fileName.search(/doc|docx/i) > -1) {
                // doc/docx 文件
                this.fileArr.push({ name: fileName, file: files[i], type: 'doc', select: false })
              }
              else if (fileName.search(/pdf/i) > -1) {
                // pdf 文件
                this.fileArr.push({ name: fileName, file: files[i], type: 'pdf', select: false })
              }
              else {
                // 其他文件
                this.fileArr.push({ name: fileName, file: files[i], type: 'file', select: false })
              }
            }
          }
        }
        // 排序，不区分大小写
        this.folderArr.sort((a, b) => { return a.name.toUpperCase() > b.name.toUpperCase() ? '1' : '-1' })
        this.fileArr.sort((a, b) => { return a.name.toUpperCase() > b.name.toUpperCase() ? '1' : '-1' })
      }
    },
    // 选中文件
    selectFile(index) {
      if (this.fileArr[index].select) {
        // 取消选中
        this.$set(this.fileArr[index], 'select', false)
        const name = this.fileArr[index].name
        for (let i = 0; i < this.selectArr.length; i++) {
          if (name === this.selectArr[i].name) {
            this.selectArr.splice(i, 1)
            break
          }
        }
      }
      else {
        // 选中
        this.$set(this.fileArr[index], 'select', true)

        // 读文件大小
        const FileInputStream = plus.android.importClass('java.io.FileInputStream')
        const fileSize = new FileInputStream(this.fileArr[index].file)
        const size = fileSize.available()
        let sizeMb = size / 1048576
        sizeMb = sizeMb.toFixed(4)

        // 获取文件的相对路径
        const Path = plus.android.invoke(this.fileArr[index].file, 'getPath')
        this.selectArr.push({ name: this.fileArr[index].name, url: Path, sizeMB: sizeMb })
      }
    },
    // 点击上传按钮
    uploadBtn() {
      this.$emit('confirm', this.selectArr)
      this.close()
    },
    // 点击返回
    backAddress() {
      // 先判断地址栈中是否还有地址
      const len = this.addressBar.length
      if (len > 1) {
        // 返回上级文件夹
        const index = len - 2
        const event = this.addressBar[index]
        this.backFolder(event, index)
      }
      else {
        // 退出文件选择
        if (this.isExit) {
          // 退出文件选择
          this.close()
          // this.$u.toast('在点击一次退出文件选择')
        }
        else {
          // 返回根目录
          this.isExit = true // 下一次再点击则退出
          this.backRoot()
          uni.showToast({
            title: '再操作一次退出文件选择',
            icon: 'none',
            duration: 1000
          })
        }
      }
    }
  }
}
</script>

<style lang="scss">
.file-outerBox {
  width: 100%;
  height: 100vh;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1070;
  padding-bottom: 40rpx;
  background-color: #fff;

  .file-titel {
    width: 100%;
    height: 80rpx;
    line-height: 80rpx;
    text-align: center;
    // background-color: #FFFFFF;
    padding: 0 32rpx;
    display: flex;
    align-items: center;
    justify-content: space-between;

    .file-nav-leftBox {
      width: 60rpx;
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;

      .file-back-img {
        width: 36rpx;
      }
    }

    .file-nav-rightBox {
      width: 60rpx;
      height: 100%;
    }
  }

  .file-address {
    width: 100%;
    height: 60rpx;
    background-color: #fbfbfb;
    padding: 0 32rpx;
    display: flex;
    color: #373737;
    font-size: 24rpx;

    .address-scroll {
      width: calc(100% - 116rpx);
      white-space: nowrap;
      height: 100%;

      .address-box {
        height: 60rpx;
        line-height: 60rpx;
        display: inline-block;

        .to-img-box {
          width: 20rpx;
        }
      }
    }

    .root-box {
      width: 116rpx;
      height: 60rpx;
      line-height: 60rpx;
      display: inline-block;
      box-shadow: 10rpx 0 10rpx -10rpx rgba(8, 8, 8, 0.3);

      .to-img-box {
        width: 20rpx;
      }
    }
  }

  .folder-box {
    height: 120rpx;
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin: 0 32rpx;
    border-bottom: 1px solid #eeeeee;

    .folder-name-box {
      width: 80%;
      display: flex;
      align-items: center;
      flex-wrap: wrap;

      .folder-img {
        width: 72rpx;
        margin-right: 16rpx;
      }

      .name-box {
        width: calc(100% - 100rpx);
        overflow: hidden;
        word-wrap: break-word;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
      }
    }

    .toFolder-img {
      width: 28rpx;
    }
  }

  .select-tips {
    width: 100%;
    height: 160rpx;
    text-align: center;
    font-size: 32rpx;
    color: #888;
    padding-top: 60rpx;
  }

  .file-box {
    height: 120rpx;
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin: 0 32rpx;
    border-bottom: 1px solid #eeeeee;

    .file-name-box {
      width: 80%;
      display: flex;
      align-items: center;

      .file-img {
        width: 72rpx;
        margin-right: 16rpx;
      }

      // .type-file{
      //  width: 60rpx;
      //  margin-left: 10rpx;
      // }
      .name-box {
        width: calc(100% - 100rpx);
        overflow: hidden;
        word-wrap: break-word;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
      }
    }

    .select-img {
      width: 32rpx;
    }
  }

  .select-foot-btn {
    width: calc(100% - 64rpx);
    margin-top: 20rpx;
  }
}
</style>
